<?php
 /**
 +------------------------------------------------------------------------------
 * Framk PHP框架
 +------------------------------------------------------------------------------
 * @package  Framk
 * @author   shawn fon <shawn.fon@gmail.com>
 +------------------------------------------------------------------------------
 */
class Cache {
	
	private $cacheDir;
	private $cacheID;	
	private $cacheTime;	
	
 /*
 +------------------------------------------------------------------------------
 * 构造方法：初始化缓存目录与缓存标识
 +------------------------------------------------------------------------------
 */	
	public function __construct($cacheDir,$cacheID) {		
		$this->cacheDir=$cacheDir;
		$this->cacheID=$cacheID;
	}

 /*
 +------------------------------------------------------------------------------
 * 魔术函数：回调数据查询操作方法：返回数据
 +------------------------------------------------------------------------------
 * 如果用户在查找时没有单独设置缓存时间，则用Config的缓存时间
 * 如果缓存目录为空则直接从数据库查询，否则从缓存中获得数据
 +------------------------------------------------------------------------------
 */	
	public function __call($method, $args){
	
		!isset($args[1])? $this->cacheTime =$GLOBALS['cacheTime'] :$this->cacheTime =$args[1] ;
		!empty($this->cacheDir)? $data = $this->findByCache($method,$args[0]):$data = $this->findByDB($method,$args[0]);	
		return $data;
	}
 /*
 +------------------------------------------------------------------------------
 * 缓存查询：判断缓存是否存在，若存在直接读取，否则生成缓存再读取；返回缓存文件内容
 +------------------------------------------------------------------------------
 * 如果调用的是查询一维数组方法而没有传递缓存唯一标识时报错
 * 创建缓存目录
 * 命名缓存文件与缓存时间文件
 * 判断是否需要生成新的缓存
 * 读取缓存
 +------------------------------------------------------------------------------
 */		
	private function findByCache($method,$sql) {

		if($method =='findOne' && empty($this->cacheID)) _error('paramsError', '缺少查询单条缓存数据的标识:',true);
		empty( $this->cacheID) ? $cacheID=md5(str_replace(' ','',$sql)):$cacheID=$this->cacheID ;
		empty( $this->cacheID) ? $timeName=str_replace('/','_',$this->cacheDir) :$timeName=$this->cacheID;
		$cacheDir = _mkdir (str_replace('/',S,CACHE.$this->cacheDir) .S);			 		
		$cacheFile= $cacheDir.$cacheID.'.php';
		$timeFile = $cacheDir .$timeName.'.txt';
				
		if($this->isCacheCheck ($cacheFile, $timeFile)){
			$content = "<?php \r\n return " . var_export ( $this->findByDB($method,$sql), true ) . "; \r\n  ?>";
			if (! file_put_contents ( $cacheFile, $content )) _error ( 'writeError' ,'写入缓存失败请检查目录权限:'. $cacheFile, true);		 		
		}				
		if (file_exists ( $cacheFile )){ return  require( $cacheFile); }else{
			_error ( 'readError', '读取缓存失败，请检查缓存文件是否存在:'.$cacheFile,true );
		}			
	}	
	
 /*
 +------------------------------------------------------------------------------
 * 直接查询数据：直接从数据库查询数据；返回查询的数据
 +------------------------------------------------------------------------------
 * 连接数据库
 * 调用数据查询方法
 +------------------------------------------------------------------------------
 */	
	private function findByDB($method,$sql){
	
		$database=_instance(FRAMK.'Database');
		if (method_exists ( $database, $method )) {
			return $database->$method($sql); 
		}else {
			_error('methodNotExist', '数据查询方法不存在:'.$method,true);
		}
	}
	
 /*
 +------------------------------------------------------------------------------
 * 缓存更新判断：判断是否需要缓存更新，返回值：true/false
 +------------------------------------------------------------------------------
 * 如果没有时间文件则创建
 * 如果缓存文件不存在 或缓存文件的修改时间小于时间文件的修改时间则返回真
 +------------------------------------------------------------------------------
 */	
	private function isCacheCheck($cacheFile, $timeFile) {

		if (! file_exists ( $timeFile )) fclose ( fopen ( $timeFile, "w" ) );	
		if (! file_exists ( $cacheFile )|| filemtime( $cacheFile )+ $this->cacheTime < filemtime( $timeFile )){

		    return true;
		}else{		
	        return false;	
		}	
	}

 /*
 +------------------------------------------------------------------------------
 * 添加数据：返回值：新增数据ID
 +------------------------------------------------------------------------------
 * 执行SQL语句
 * 更新时间文件 
 +------------------------------------------------------------------------------
 */	
 	public function insert($sql) {
		
		$result= _instance(FRAMK.'Database')->updt($sql);	
		if(!empty($this->cacheDir)&& $result>0){					
			$cacheDir = _mkdir ( str_replace('/',S,CACHE.$this->cacheDir) .S);
			fclose ( fopen ( $cacheDir .str_replace('/','_',$this->cacheDir).'.txt', "w" ) );						
		}
		return $result;	
	}
 /*
 +------------------------------------------------------------------------------
 * 修改数据：返回值：更新的数据行数
 +------------------------------------------------------------------------------
 * 判断是否存在缓存唯一标识
 * 执行SQL语句
 * 更新时间文件 
 +------------------------------------------------------------------------------
 */	
 	public function update($sql) {
		
		if(empty( $this->cacheID)) _error('paramsError', '缺少更新缓存数据的标识:',true);
		$result= _instance(FRAMK.'Database')->updt($sql);		
		if(!empty($this->cacheDir)&& $result >=0){				
			$cacheDir =  str_replace('/',S,CACHE.$this->cacheDir) .S;
			fclose ( fopen ( $cacheDir .str_replace('/','_',$this->cacheDir).'.txt', "w" ) );		
			fclose ( fopen ( $cacheDir .$this->cacheID.'.txt', "w" ) );			
		}
		return $result;	
	}			
 /*
 +------------------------------------------------------------------------------
 * 删除数据：返回值：删除数据的行数
 +------------------------------------------------------------------------------
 * 判断是否存在缓存唯一标识
 * 执行SQL语句
 * 更新时间文件 
 * 删除缓存文件
 +------------------------------------------------------------------------------
 */	
 	public function delete($sql) {
	
		if(empty( $this->cacheID)) _error('paramsError', '缺少删除缓存的标识:',true);		
		$result= _instance(FRAMK.'Database')->updt($sql);
		if(!empty($this->cacheDir)&& $result>0){				
			$cacheDir =  str_replace('/',S,CACHE.$this->cacheDir) .S;
			fclose ( fopen ( $cacheDir .str_replace('/','_',$this->cacheDir).'.txt', "w" ) );		
			@unlink($cacheDir .$this->cacheID.'.txt');
			@unlink($cacheDir .$this->cacheID.'.php');
		}
		return $result;	
	}
		
 /*  +------------------------------------------------------------------------------ */		
	} //
?>